#!/bin/bash
#
# Script for building a cross compilation toolchain for ARM.
#
# Copyright 2009, Roberto Gordo Saez (roberto.gordo@gmail.com)
#
# This script is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This script is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
set -x
set -e
umask 022

build=`gcc -dumpmachine`
target=arm-none-linux-gnueabi
cc_for_build=gcc-4.2

while getopts b:t:c: opt
do
        case "$opt" in
	b) build="$OPTARG" ;;
        t) target="$OPTARG" ;;
	c) cc_for_build="$OPTARG" ;;
        \?) exit 1 ;;
        esac
done
shift `expr $OPTIND - 1`

builddir=`pwd`
if echo "$target" | grep -q '^arm-'
then
	linux_arch=arm
else
	linux_arch=i386
fi

test -z "$TOOLCHAIN_VERSION" && TOOLCHAIN_VERSION='2008.12.rgs2'
toolchain_name="toolchain-$target-glibc-$TOOLCHAIN_VERSION"
test -z "$INSTALLDIR" && INSTALLDIR="/usr/local/$toolchain_name"
installdir="$INSTALLDIR"

tmpinstalldir="$builddir/install"

binutils_src_pkg='binutils-2.18.tar.bz2'
binutils_src_dir='binutils-2.18'
linux_src_pkg='linux-2.6.24.7.tar.bz2'
linux_src_dir='linux-2.6.24.7'
gcc_src_pkg='gcc-2008q1-126.tar.bz2'
gcc_src_dir='gcc-4.2'
glibc_src_pkg='glibc-2008q1-126.tar.bz2'
glibc_src_dir='glibc-2.5'
glibc_ports_src_pkg='glibc_ports-2008q1-126.tar.bz2'
glibc_ports_src_dir='glibc-ports-2.5'
expat_src_pkg='expat-2.0.1.tar.bz2'
expat_src_dir='expat-2.0.1'
gdb_src_pkg='gdb-6.8.tar.bz2'
gdb_src_dir='gdb-6.8'


orig_path="$PATH"
host="$build"

reset_env()
{
	export PATH="$installdir/bin:$orig_path"
	export CC="$cc_for_build"
	export BUILD_CC="$cc_for_build"
	unset CXX
	unset AR
	unset RANLIB
	unset AR_FOR_TARGET
	unset NM_FOR_TARGET
	unset OBJDUMP_FOR_TARET
	unset STRIP_FOR_TARGET
}

clean_builddir()
{
	rm -rf "$linux_src_dir"
	rm -rf "$binutils_src_dir"
	rm -rf "$glibc_src_dir" "$glibc_ports_src_dir"
	rm -rf "$gcc_src_dir"
	rm -rf "$expat_src_dir"
	rm -rf "$gdb_src_dir"
	rm -rf build "$tmpinstalldir"
	rm -rf "$installdir" || true
}

build_binutils()
{
	mkdir build
	pushd build
	"$builddir/$binutils_src_dir"/configure --prefix="$installdir" --build="$build" --host="$host" --target="$target" --disable-nls --with-sysroot="$installdir"/sysroot --program-prefix="$target"-
	make
	make install
	popd
	rm -rf build
}

install_kernel_headers()
{
	mkdir -p "$tmpinstalldir"/kernel-headers
	pushd "$linux_src_dir"
	make ARCH="$linux_arch" CROSS_COMPILE="$installdir"/bin/"$target"- INSTALL_HDR_PATH="$tmpinstalldir"/kernel-headers headers_install
	popd

	mkdir -p "$installdir"/sysroot/usr/include
	pushd "$tmpinstalldir"/kernel-headers/include
	mv linux "$installdir"/sysroot/usr/include
	mv asm-generic "$installdir"/sysroot/usr/include
	mv asm "$installdir"/sysroot/usr/include
	popd
	rm -rf "$tmpinstalldir"/kernel-headers
}

build_gcc()
{
	mkdir build
	pushd build
	"$builddir/$gcc_src_dir"/configure --prefix="$installdir" --build="$build" --host="$host" --target="$target" --disable-libmudflap --disable-libssp --with-gnu-as --with-gnu-ld --disable-nls --enable-symvers=gnu --enable-__cxa_atexit --disable-libstdcxx-pch --disable-libgomp --with-sysroot="$installdir"/sysroot --with-build-sysroot="$installdir"/sysroot --with-build-time-tools="$installdir/$target/bin" --disable-bootstrap --program-prefix="$target"- --enable-poison-system-directories "$@"
	make LDFLAGS_FOR_TARGET=--sysroot="$installdir"/sysroot CPPFLAGS_FOR_TARGET=--sysroot="$installdir"/sysroot build_tooldir="$installdir"/sysroot
	make install
	popd
	rm -rf build
}

build_glibc()
{
	local subdir
	local cflags
	if test -n "$1" -a -n "$2"
	then
		subdir="$1"
		shift
		cflags="$@"
	fi
	export CC="$target-gcc -fgnu89-inline $cflags"
	export CXX="$target-cxx $cflags"
	export AR="$target-ar"
	export RANLIB="$target-ranlib"
	mkdir build
	pushd build
	"$builddir/$glibc_src_dir"/configure --prefix=/usr --with-headers="$installdir"/sysroot/usr/include --build="$build" --host="$target" --disable-profile --without-gd --without-cvs --enable-add-ons --enable-kernel=2.6.14
	make
	mkdir -p "$installdir/sysroot/$subdir"
	make install_root="$installdir/sysroot/$subdir" install
	popd
	rm -rf build
	reset_env
}

build_expat()
{
	mkdir build
	pushd build
	mkdir -p "$tmpinstalldir"/expat
	"$builddir/$expat_src_dir"/configure --prefix="$tmpinstalldir"/expat --build="$build" --host="$host" --target="$target" --disable-shared --disable-nls
	make
	make install
	popd
	rm -rf build
}

build_gdb()
{
	mkdir build
	pushd build
	"$builddir/$gdb_src_dir"/configure --prefix="$installdir" --build="$build" --host="$host" --target="$target" --disable-sim --disable-nls --with-libexpat-prefix="$tmpinstalldir"/expat --program-prefix="$target"-
	make
	make install
	popd
	rm -rf build
}

build_gdbserver()
{
	local subdir
	local cflags
	if test -n "$1" -a -n "$2"
	then
		subdir="$1"
		shift
		cflags="$@"
	fi
	export CC="$target-gcc $cflags"
	mkdir build
	pushd build
	"$builddir/$gdb_src_dir"/gdb/gdbserver/configure --prefix=/usr --mandir=/usr/share/man --build="$build" --host="$target" --disable-shared --disable-sim
	make
	make DESTDIR="$installdir/sysroot/$subdir" install
	popd
	rm -rf build
	reset_env
}

finish_installation()
{
	local b

	rm -f "$installdir"/bin/*gccbug*
	rm -f "$installdir/bin/$target-$target"*
	rm -rf "$installdir"/sysroot/usr/info
	rm -rf "$installdir"/sysroot/*/usr/info
	rm -rf "$installdir"/sysroot/*/usr/man
	rm -rf "$installdir"/info
	rm -f "$installdir"/lib/libiberty.a

	if test -d "$installdir"/include
	then
		cp -a "$installdir"/include "$installdir/$target"
		rm -rf "$installdir"/include
	fi

	cp -a "$installdir"/share/doc "$installdir"
	cp -a "$installdir"/share/man "$installdir"
	rm -rf "$installdir"/share

	rm -rf "$installdir/$target"/bin
	mkdir -p "$installdir/$target"/bin
	pushd "$installdir/$target"/bin
	for i in "$installdir"/bin/"$target"-*
	do
		b=`basename "$i"`
		ln "$i" ${b##$target-}
	done
	popd

	for commondir in usr/share usr/include
	do
		for d in "$installdir"/sysroot/*/"$commondir"
		do
			if test -d "$d"
			then
				rm -rf "$d"
				ln -s ../../"$commondir" "$d"
			fi
		done
	done
	cp "$builddir"/README.txt "$installdir"
}

strip_files()
{
	for f in `find "$installdir"/bin "$installdir"/libexec/gcc -type f`
	do
		if file "$f" | grep -q 'not stripped'
		then
			strip "$f"
		fi
	done
}

cd "$builddir"
reset_env
clean_builddir
mkdir -p "$installdir"

tar xjf "$binutils_src_pkg"
pushd "$binutils_src_dir"
cat "$builddir"/binutils-*.diff | patch -p1
autoreconf
popd
build_binutils
rm -rf "$binutils_src_dir"

tar xjf "$linux_src_pkg"
install_kernel_headers
rm -rf "$linux_src_dir"

tar xjf "$gcc_src_pkg"
pushd "$gcc_src_dir"
patch -p1 < "$builddir"/gcc_no-poison-ld.patch
popd
build_gcc --disable-threads --disable-shared --enable-languages=c --without-headers --with-newlib --with-float=soft --with-cpu=arm926ej-s

tar xjf "$glibc_src_pkg"
tar xjf "$glibc_ports_src_pkg"
mv "$glibc_ports_src_dir" "$glibc_src_dir"/ports
pushd "$glibc_src_dir"
patch -p1 < "$builddir"/glibc_gcc-eh-cross.patch
popd

build_glibc

build_gcc --enable-threads --enable-shared --enable-languages=c,c++,java --with-float=soft --with-cpu=arm926ej-s
rm -rf "$gcc_src_dir"

tar xjf "$expat_src_pkg"
build_expat
rm -rf "$expat_src_dir"

tar xjf "$gdb_src_pkg"
pushd "$gdb_src_dir"
cat "$builddir"/gdb-*.diff | patch -p1
autoreconf
popd
build_gdb

build_gdbserver

finish_installation
rm -rf "$tmpinstalldir"
strip_files

exit 0
